PSDK 사용자 정의 위젯(Custom Widget) 개발 안내서 (2025-09-26)
1. 서론: 표준 위젯을 넘어, 사용자 정의 위젯의 세계로
1.1 위젯의 진화와 사용자 경험(UX)의 패러다임 변화
소프트웨어 개발 키트(Software Development Kit, SDK)는 특정 플랫폼을 위한 애플리케이션 개발에 필요한 도구, 라이브러리, 문서, API 등을 집약한 통합 패키지다.1 SDK의 본질적 역할은 사전 빌드된 구성 요소와 프레임워크를 제공함으로써 개발자가 바퀴를 재발명하는 데 드는 시간과 노력을 줄이고, 핵심 비즈니스 로직 구현에 집중할 수 있도록 지원하는 것이다. 이를 통해 개발 효율성을 극대화하고, 제품 출시 기간을 단축하며, 전반적인 개발 비용을 절감하는 효과를 가져온다.1
이러한 SDK가 제공하는 수많은 구성 요소 중, 위젯(Widget)은 현대 모바일 및 웹 환경에서 사용자 경험(UX)의 패러다임을 바꾸는 핵심적인 요소로 자리 잡았다. 위젯은 애플리케이션의 핵심 정보나 기능을 앱을 실행하지 않고도 홈 화면이나 잠금 화면 등에서 직접 접근하고 상호작용할 수 있게 만든 소형 앱 뷰(mini app view)다.4 날씨 정보, 캘린더 일정, 주식 시세 등을 실시간으로 확인하거나 음악을 제어하는 등의 간단한 작업을 앱 실행 과정 없이 즉시 수행하게 함으로써, 사용자의 편의성을 극대화하고 앱에 대한 지속적인 인게이지먼트를 유도하는 강력한 수단이 된다.6
위젯의 기술적 진화는 정적인 정보 표시에서 동적인 상호작용으로의 전환으로 요약할 수 있다. 초기 위젯은 정해진 정보를 주기적으로 업데이트하여 보여주는 단방향 정보 전달자의 역할에 머물렀다. 그러나 사용자들이 더 빠르고 즉각적인 피드백을 요구하고, 앱을 실행하는 과정 자체를 번거롭게 느끼는 ‘앱 피로(App Fatigue)’ 현상이 심화됨에 따라 플랫폼은 위젯의 역할을 재정의하기 시작했다. Android 12와 Jetpack Glance, 그리고 iOS 14의 WidgetKit 도입 이후, 특히 iOS 17에서 상호작용 기능이 대폭 강화되면서 위젯은 단순한 정보창을 넘어 독립적인 기능을 수행하는 마이크로 인터페이스(Micro-Interface)로 진화하고 있다.6 이제 위젯은 단순히 정보를 보여주는 것을 넘어, 사용자의 간단한 작업을 위젯 내에서 직접 완료할 수 있는 새로운 상호작용 채널로 기능하며, 이는 앱의 가치를 사용자에게 지속적으로 상기시키는 중요한 비즈니스 기회를 창출한다.
1.2 표준 위젯의 한계와 사용자 정의(Customization)의 필연성
대부분의 플랫폼은 개발자가 손쉽게 사용할 수 있는 표준 위젯 툴킷을 제공한다.8 이러한 표준 위젯은 일반적인 사용 사례를 충족시키고 빠른 개발을 가능하게 하지만, 동시에 명백한 한계를 내포한다. 이러한 한계는 기능, 디자인, 상호작용의 세 가지 측면에서 두드러진다.
첫째, 기능적 제약이다. 표준 위젯은 플랫폼이 미리 정의한 기능 범위 내에서만 동작한다. 복잡한 데이터 시각화, 다단계 상호작용, 또는 앱 고유의 비즈니스 로직과 깊게 연동되는 기능을 구현하는 데에는 한계가 있다. 예를 들어, Android 표준 위젯은 터치와 수직 스와이프 외의 복합적인 제스처를 지원하는 데 제한이 따른다.10 이로 인해 개발자는 차별화된 사용자 경험을 제공하는 데 어려움을 겪게 된다.11
둘째, 디자인의 제약이다. 표준 위젯은 해당 플랫폼의 디자인 가이드라인을 엄격하게 따르도록 설계되어 있다.11 이는 플랫폼 전체의 시각적 일관성을 유지하는 데는 도움이 되지만, 개별 앱의 고유한 브랜딩과 디자인 아이덴티티를 위젯에 온전히 담아내기 어렵게 만든다. 정해진 레이아웃 구조, 제한된 폰트 및 색상 팔레트는 창의적인 디자인 표현을 가로막는 요소로 작용한다. 때로는 텍스트 크기나 색상 대비율 같은 접근성 요구사항을 충족시키지 못하는 경우도 발생할 수 있다.11
마지막으로, 상호작용의 한계다. 앞서 언급했듯, 표준 위젯에서 지원하는 상호작용은 제한적이다. 이는 사용자가 위젯을 통해 수행할 수 있는 작업의 범위를 좁히고, 결국 위젯을 단순한 ‘앱 바로가기’ 수준으로 전락시킬 위험이 있다.
이러한 표준 위젯의 본질적인 한계를 극복하고, 앱의 핵심 가치를 사용자에게 가장 효과적이고 매력적인 방식으로 전달하기 위해 사용자 정의 위젯(Custom Widget) 개발은 더 이상 선택이 아닌 필수가 되었다. 사용자 정의 위젯은 개발자에게 완전한 제어권을 부여하여, 앱의 정체성을 반영한 독창적인 디자인과 혁신적인 기능을 구현할 수 있는 무한한 가능성을 열어준다.
각 플랫폼이 위젯에 부여하는 자유도는 해당 플랫폼의 근본적인 생태계 철학을 반영한다는 점을 이해하는 것이 중요하다. Apple의 iOS는 WidgetKit 가이드라인을 통해 일관되고 높은 품질의 사용자 경험을 보장하기 위해 디자인과 업데이트 주기에 대해 비교적 엄격한 규칙을 제시한다.12 반면, Google의 Android는 개발자에게 높은 자유도를 부여하여 더 다양한 시도를 가능하게 하지만, 이는 자칫 파편화된 사용자 경험으로 이어질 수 있는 트레이드오프를 가진다.11 웹 위젯은 기술적으로 가장 자유롭지만, 호스트 페이지와의 통합, 보안, 그리고 다양한 브라우저 환경에서의 호환성 확보가 핵심 과제가 된다.15 따라서 성공적인 사용자 정의 위젯 개발은 단순히 기술 구현을 넘어, 대상 플랫폼의 철학과 생태계를 깊이 이해하고 그 안에서 최적의 균형점을 찾는 전략적 접근을 요구한다.
2. 사용자 정의 위젯의 핵심 아키텍처와 생명주기
사용자 정의 위젯을 성공적으로 개발하기 위해서는 특정 플랫폼의 API를 학습하기에 앞서, 그 기저에 깔린 보편적인 아키텍처 원리와 동작 방식을 이해하는 것이 필수적이다. 플랫폼마다 용어와 구현 방식은 다르지만, 모든 위젯 시스템은 유사한 핵심 구성 요소와 생명주기 모델을 공유한다.
2.1 플랫폼 독립적인 위젯 구성 요소 분석
사용자 정의 위젯의 아키텍처는 일반적으로 네 가지 핵심 구성 요소로 나눌 수 있다.
-
데이터 제공자 (Data Provider): 위젯에 표시될 데이터를 생성하고 시스템에 제공하는 책임을 지는 컴포넌트다. 이는 위젯의 ’두뇌’에 해당한다. Android에서는
BroadcastReceiver를 상속하는AppWidgetProvider클래스가 이 역할을 수행하며, 시스템이 발송하는 업데이트 관련 브로드캐스트 인텐트를 수신하여 위젯의 상태를 갱신한다.14 iOS의 WidgetKit에서는TimelineProvider프로토콜이 동일한 역할을担う. 시스템의 요청에 따라 미래의 특정 시점에 위젯이 어떤 상태를 가져야 하는지를 정의하는 타임라인(Timeline)을 생성하여 반환한다.18 웹 환경에서는 백엔드 API와의 통신을 담당하는 JavaScript 모듈이나 React의 데이터 페칭 훅(useEffect,useSWR등)이 데이터 제공자의 역할을 수행한다.20 -
뷰/레이아웃 (View/Layout): 위젯의 시각적 표현, 즉 사용자 인터페이스(UI)를 정의하는 부분이다. Android는 XML 레이아웃 파일을 통해 정적인 구조를 정의하고,
RemoteViews라는 특수한 객체를 사용하여 이 레이아웃을 동적으로 제어한다.RemoteViews는 다른 프로세스(예: 홈 스크린 런처)에서 UI를 안전하게 렌더링하기 위해 직렬화가 가능한 뷰 계층 구조 정보를 담고 있다.5 반면, iOS는 현대적인 선언적 UI 프레임워크인 SwiftUI를 사용하여 위젯 뷰를 구성한다. 이는 코드 기반으로 유연하고 동적인 UI를 손쉽게 제작할 수 있게 해준다.7 웹 위젯은 전통적인 웹 기술인 HTML 템플릿과 CSS를 사용하여 UI를 정의하며, JavaScript를 통해 동적으로 조작한다.16 -
설정/메타데이터 (Configuration/Metadata): 위젯의 기본적인 속성과 동작 방식을 시스템에 알리는 역할을 한다. 여기에는 위젯의 최소/최대 크기, 기본 업데이트 주기, 초기 레이아웃, 이름, 설명 등이 포함된다. Android에서는
AppWidgetProviderInfo라는 별도의 XML 파일에 이러한 메타데이터를 상세히 기술한다.14 iOS에서는Widget프로토콜을 준수하는 구조체 내에서StaticConfiguration또는IntentConfiguration객체를 생성하여 Swift 코드로 직접 위젯의 종류, 표시 이름, 지원 크기 등을 설정한다.18 웹 위젯의 경우,widget.json과 같은 표준화된 메타데이터 파일을 사용하거나 JavaScript 설정 객체를 통해 이를 관리할 수 있다.15 -
사용자 설정 액티비티/화면 (Configuration Activity/Screen): 모든 위젯에 필수적인 요소는 아니지만, 사용자가 위젯을 처음 추가할 때 개인화된 설정을 할 수 있도록 제공하는 선택적 UI다. 예를 들어, 날씨 위젯에 특정 도시를 설정하거나, 주식 위젯에 관심 종목을 등록하는 기능이 이에 해당한다. 이 설정 화면을 통해 수집된 정보는 위젯의 동작과 표시에 직접적인 영향을 미친다.14
이러한 구성 요소들은 서로 유기적으로 작동하며 위젯의 전체 기능을 완성한다. 이들의 관계를 이해하는 것은 플랫폼별 구현의 차이점을 넘어서는 위젯 개발의 근본적인 통찰을 제공한다. 위젯 아키텍처의 핵심은 본질적으로 ’프로세스 간 통신(Inter-Process Communication, IPC)’과 ’상태의 비동기적 동기화’에 기반한다. 애플리케이션은 보안과 안정성을 위해 운영체제에 의해 각각 격리된 프로세스 공간에서 실행되며, 위젯을 호스팅하는 홈 스크린 역시 별개의 시스템 프로세스다. 만약 위젯이 앱 프로세스에서 직접 UI를 렌더링한다면, 해당 앱의 오류나 비정상 종료가 홈 스크린 전체 시스템을 마비시키는 심각한 문제를 야기할 수 있다.
이러한 문제를 해결하기 위해 플랫폼들은 UI 렌더링에 필요한 ’데이터와 명령어 묶음’을 직렬화하여 프로세스 경계를 넘어 호스트 프로세스로 안전하게 전달하는 방식을 채택했다. Android의 RemoteViews는 뷰 계층 구조와 그릴 내용을 담은 명령어 집합이며 17, iOS의 TimelineEntry는 특정 시점에 그려야 할 뷰의 상태(데이터)를 담고 있는 스냅샷이다.18 이처럼 위젯은 앱의 UI를 직접 그리는 것이 아니라, 렌더링에 필요한 상태 객체를 비동기적으로 전달하는 방식으로 동작한다. 따라서 위젯 개발자는 UI를 ’상태(state)’의 함수로 간주하고, 상태가 변경될 때마다 전체 UI를 새로 그리는 데 필요한 데이터를 효율적으로 패키징하여 전달하는 선언적(Declarative) 패러다임에 입각하여 접근해야 한다.
다음 표는 주요 플랫폼별 위젯 핵심 구성 요소의 역할과 명칭을 비교하여 아키텍처에 대한 통합적인 이해를 돕는다.
표 1: 주요 플랫폼별 사용자 정의 위젯 핵심 구성 요소 비교
| 기능 분류 | Android | iOS (WidgetKit) | Web (JavaScript) |
|---|---|---|---|
| 핵심 로직/제공자 | AppWidgetProvider (BroadcastReceiver) | TimelineProvider 프로토콜 | JavaScript 모듈 / React Component |
| 메타데이터 정의 | AppWidgetProviderInfo (XML) | WidgetConfiguration (in Swift) | widget.json 또는 JS 객체 |
| UI 레이아웃 | XML Layout + RemoteViews | SwiftUI View | HTML 템플릿 + CSS |
| 업데이트 관리 | AppWidgetManager | WidgetCenter, TimelineReloadPolicy | setInterval, Event Listeners, API Polling |
| 사용자 설정 | Configuration Activity | App Intents, IntentConfiguration | HTML Form in iframe / SDK 제공 UI |
| 상호작용 처리 | PendingIntent | Button, Toggle with App Intents | JavaScript Event Handlers (onclick 등) |
이 표는 플랫폼 간의 상이한 용어와 클래스 이름 이면에 존재하는 공통적인 아키텍처 패턴을 명확히 보여준다. 예를 들어, Android의 AppWidgetProvider와 iOS의 TimelineProvider는 명칭은 다르지만 ’시스템의 요청에 응답하여 위젯의 다음 상태를 제공한다’는 동일한 핵심 역할을 수행한다. 이처럼 역할 중심으로 아키텍처를 이해하면, 특정 플랫폼 경험을 가진 개발자가 다른 플랫폼의 위젯 시스템을 훨씬 빠르고 효과적으로 학습할 수 있다.
2.2 위젯의 생명주기(Lifecycle) 모델 해부
위젯은 사용자가 홈 스크린에 추가하는 순간부터 제거될 때까지 명확한 생명주기를 따른다. 이 생명주기를 이해하는 것은 리소스를 효율적으로 관리하고 정확한 시점에 콘텐츠를 업데이트하는 데 매우 중요하다.
-
생성 (Creation/Binding): 생명주기는 사용자가 위젯 갤러리에서 특정 위젯을 선택하여 홈 스크린에 배치할 때 시작된다. 이 시점에서 시스템은 해당 위젯의 인스턴스를 생성하고,
AppWidgetHost와 같은 호스트 관리자를 통해 위젯 인스턴스를 식별할 고유 ID를 할당한다.26 만약 위젯이 사용자 설정을 요구하도록 정의되었다면(Configuration Activity/Screen), 이 단계에서 설정 화면이 사용자에게 제시된다. 사용자가 설정을 완료하고 확인하면 위젯이 홈 스크린에 최종적으로 추가되고, 사용자가 설정을 취소하면 생성 과정이 중단된다.14 -
업데이트 (Update): 위젯의 핵심 기능으로, 표시되는 콘텐츠를 최신 상태로 유지하는 과정이다. 업데이트는 여러 가지 방식으로 촉발될 수 있다.
-
주기적 업데이트: 가장 일반적인 방식으로, 위젯 메타데이터에 정의된 고정된 시간 간격에 따라 시스템이 자동으로 업데이트를 요청한다. Android의
updatePeriodMillis속성 14 또는 iOS의
TimelineReloadPolicy 18가 이에 해당한다. 배터리 소모와 시스템 부하를 최소화하기 위해, 플랫폼은 가능한 한 업데이트 주기를 길게 설정할 것을 강력히 권장한다.12
-
이벤트 기반 업데이트: 특정 이벤트가 발생했을 때 위젯을 업데이트하는 방식이다. 예를 들어, 메인 앱에서 데이터가 변경되었을 때, 시스템의 시간대나 언어가 변경되었을 때, 또는 원격 푸시 알림을 수신했을 때 위젯을 즉시 갱신할 수 있다.11
-
사용자 상호작용 기반 업데이트: 사용자가 위젯 내의 새로고침 버튼을 누르거나 특정 UI 요소와 상호작용했을 때 업데이트가 트리거될 수 있다.
-
크기 변경 (Resize): 사용자가 홈 스크린에서 위젯의 경계를 끌어 크기를 조절할 때 발생하는 이벤트다. 위젯 메타데이터에
resizeMode속성을horizontal,vertical, 또는horizontal|vertical로 설정하여 크기 조절 가능 여부와 방향을 지정할 수 있다.14 이 이벤트가 발생하면, 위젯은 변경된 크기에 맞춰 레이아웃과 콘텐츠를 최적화하여 다시 렌더링해야 한다. -
소멸 (Deletion): 사용자가 홈 스크린에서 위젯을 길게 눌러 제거할 때 생명주기가 종료된다. 이 이벤트가 발생하면 시스템은 위젯과 관련된 모든 리소스(예: 할당된 고유 ID, 예약된 업데이트 등)를 정리하고 해제한다. 개발자는 이 시점에 위젯 인스턴스와 관련하여 저장했던 영구 데이터나 설정을 정리하는 로직을 수행할 수 있다. Android에서는
AppWidgetManager의deleteAppWidgetId()메소드가 호출되어 ID를 시스템에서 해제한다.26
이러한 생명주기 이벤트들은 위젯이 시스템 리소스를 효율적으로 사용하며, 사용자와의 상호작용에 적절히 반응하도록 설계된 핵심적인 제어 메커니즘이다.
3. 플랫폼별 사용자 정의 위젯 개발: 심층 가이드
이 장에서는 Android, iOS, Web 각 플랫폼의 고유한 특성에 맞춰 사용자 정의 위젯을 개발하는 구체적인 방법론을 상세한 코드 예시와 함께 단계별로 탐구한다. 각 플랫폼의 UI 업데이트 메커니즘은 해당 플랫폼이 추구하는 성능 최적화 철학을 깊이 반영하고 있으므로, 이를 이해하는 것이 핵심이다.
3.1 Android 플랫폼: AppWidgetProvider와 RemoteViews 활용
Android 위젯은 성숙하고 유연한 시스템을 제공하지만, RemoteViews의 특성상 프로세스 간 통신(IPC)에 대한 이해가 필수적이다. Android의 UI 업데이트 메커니즘은 전체 UI를 매번 새로 그리는 대신, 변경이 필요한 부분에 대한 ‘명령’(setTextViewText, setImageViewResource 등)을 RemoteViews 객체에 담아 홈 스크린 프로세스로 전달하는 방식이다. 이는 IPC 비용을 최소화하여 시스템 효율성을 높이려는 설계 철학을 반영한다.
- 프로젝트 설정:
-
build.gradle설정: 특별한 의존성 추가는 필요 없으나, Jetpack Glance와 같은 최신 라이브러리를 사용하려면 관련 의존성을 추가해야 한다. -
AndroidManifest.xml선언: 위젯의 핵심인AppWidgetProvider를<receiver>태그로 등록해야 한다. 이 태그는 시스템에 위젯의 존재와 이벤트를 수신할 컴포넌트를 알리는 역할을 한다.
XML
<receiver
android:name=".ExampleAppWidgetProvider"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/example_appwidget_info" />
</receiver>
meta-data 태그는 위젯의 속성을 정의하는 AppWidgetProviderInfo XML 파일을 가리킨다.14
- AppWidgetProviderInfo XML 상세 분석:
res/xml/ 디렉터리에 위치하며 위젯의 정적 속성을 정의한다.
XML
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="180dp"
android:minHeight="110dp"
android:updatePeriodMillis="86400000"
android:previewImage="@drawable/example_appwidget_preview"
android:initialLayout="@layout/example_appwidget"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:targetCellWidth="3"
android:targetCellHeight="2">
</appwidget-provider>
-
minWidth,minHeight: 위젯의 최소 크기를 dp 단위로 지정한다.14 -
updatePeriodMillis: 주기적 업데이트 간격을 밀리초 단위로 설정한다. 배터리 보호를 위해 안드로이드는 이 값을 최소 30분(1800000ms)으로 강제한다.14 -
initialLayout: 위젯이 처음 추가될 때 표시될 레이아웃 리소스를 지정한다. -
resizeMode:horizontal및vertical조합으로 크기 조절 가능 여부를 설정한다.5 -
targetCellWidth,targetCellHeight: Android 12 이상에서 그리드 셀 단위의 기본 크기를 지정한다.5 -
AppWidgetProvider 클래스 구현:
BroadcastReceiver를 상속하며, 위젯의 생명주기 관련 콜백 메소드를 오버라이드하여 로직을 구현한다.
Java
public class ExampleAppWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
// 위젯 UI 업데이트 로직
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
views.setTextViewText(R.id.appwidget_text, "UPDATED TEXT");
// 클릭 이벤트 설정
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.appwidget_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
// onEnabled(), onDisabled(), onDeleted() 등 다른 콜백 구현
}
onUpdate()는 주기적 업데이트 또는 수동 업데이트 요청 시 호출되는 가장 중요한 메소드다.14
- RemoteViews를 이용한 UI 제어:
RemoteViews는 다른 프로세스에서 렌더링될 뷰의 레이아웃과 내용을 기술하는 객체다. setTextViewText(), setImageViewResource(), setOnClickPendingIntent() 등 제한된 메소드만을 사용하여 UI를 조작할 수 있다.17 이는 보안과 성능을 위한 제약이다.
- 실습 예제: GitHub에서 제공되는 다양한 예제 프로젝트를 통해 실제 구현 사례를 참고할 수 있다. 예를 들어, 조수 시간을 보여주는 위젯, 사용자 정의 아날로그 시계, 차트 라이브러리 위젯 등은
AppWidgetProvider와RemoteViews의 실제 활용법을 이해하는 데 큰 도움이 된다.27
3.2 iOS 플랫폼: WidgetKit과 SwiftUI의 조화
iOS 위젯 개발은 WidgetKit 프레임워크와 SwiftUI를 중심으로 이루어진다. WidgetKit의 핵심 철학은 ‘예측 기반’ UI 업데이트다. 개발자는 TimelineProvider를 통해 미래의 특정 시점에 위젯이 보여줘야 할 상태 스냅샷(TimelineEntry)의 목록, 즉 타임라인을 시스템에 미리 제공한다. 시스템은 이 타임라인을 바탕으로 정해진 시간에 효율적으로 위젯을 렌더링하며, 잦은 백그라운드 실행을 피해 배터리 소모를 최소화한다.
- 프로젝트 설정:
-
Widget Extension 추가: 기존 Xcode 프로젝트에서
File > New > Target을 선택하고 ‘Widget Extension’ 템플릿을 추가한다.18 -
App Groups 설정: 메인 앱과 위젯 익스텐션 간에 데이터를 안전하게 공유하기 위해 ‘Signing & Capabilities’ 탭에서 동일한 App Group을 활성화해야 한다.
UserDefaults나 Core Data를 공유하는 데 필수적이다.7
-
WidgetKit의 핵심 프로토콜 이해:
-
Widget: 위젯의 구성을 정의하는 최상위 진입점이다.body프로퍼티 내에서StaticConfiguration(사용자 설정 불필요) 또는IntentConfiguration(사용자 설정 필요)을 반환한다.7 -
TimelineProvider: 위젯의 데이터와 업데이트 시점을 관리하는 핵심 프로토콜이다.18 -
placeholder(in:): 위젯이 로딩 중일 때 표시할 기본 뷰의 데이터를 제공한다. -
getSnapshot(in:completion:): 위젯 갤러리에서 위젯을 미리보기 형태로 보여줄 때 사용될 단일 데이터를 제공한다. -
getTimeline(in:completion:): 현재 시점 이후의 위젯 업데이트 계획(타임라인)을 생성하여 시스템에 전달한다. -
TimelineEntry: 특정date에 위젯이 표시해야 할 모든 데이터를 담는 모델 구조체다.Date타입의date프로퍼티를 반드시 포함해야 한다.7 -
SwiftUI를 활용한 위젯 뷰 제작:
위젯의 UI는 전적으로 SwiftUI로 작성된다. Text, Image, VStack, HStack, ZStack 등 기본적인 뷰와 스택을 조합하여 레이아웃을 구성한다.21 위젯은
systemSmall, systemMedium, systemLarge 등 여러 크기(family)를 지원할 수 있으며, @Environment(\.widgetFamily) 프로퍼티를 사용하여 현재 크기에 맞는 뷰를 동적으로 보여줘야 한다.13
Swift
struct ExampleWidgetEntryView : View {
var entry: Provider.Entry
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case.systemSmall:
SmallWidgetView(entry: entry)
case.systemMedium:
MediumWidgetView(entry: entry)
default:
Text("Unsupported size")
}
}
}
- 설정 가능(Configurable) 위젯 구현:
사용자가 위젯의 내용을 직접 선택하게 하려면 IntentConfiguration을 사용해야 한다. 이를 위해 커스텀 AppIntent를 정의하고, @Parameter 프로퍼티 래퍼를 사용하여 설정 가능한 속성을 추가한다. 예를 들어, 특정 GitHub 저장소를 선택하는 위젯을 만든다면, 저장소 이름을 String 타입의 파라미터로 정의할 수 있다. EntityQuery를 구현하면 API를 통해 동적인 선택 옵션 목록을 사용자에게 제공할 수도 있다.25
- 실습 예제: GitHub에는 WidgetKit을 활용한 다양한 오픈소스 프로젝트가 있다. iOS 14부터 최신 iOS 17의 Live Activity까지 다양한 기능을 구현한 예제들을 통해 WidgetKit의 실제 적용 사례를 학습할 수 있다.32
3.3 Web (JavaScript) 플랫폼: 유연성과 이식성
웹 위젯은 특정 운영체제에 종속되지 않고, HTML, CSS, JavaScript라는 표준 웹 기술을 사용하여 구현되므로 최고의 유연성과 이식성을 자랑한다. React와 같은 현대적인 프레임워크는 웹 위젯 개발을 컴포넌트 기반으로 체계화하여 생산성을 크게 향상시켰다. 웹 위젯의 UI 업데이트는 React의 가상 DOM(Virtual DOM)과 같은 메커니즘을 통해 효율적으로 이루어진다. 상태가 변경되면, 가상 DOM은 이전 상태와 현재 상태를 비교(diffing)하여 실제 DOM에는 변경된 부분만 최소한으로 반영함으로써 렌더링 성능을 최적화한다.
- 순수 JavaScript를 이용한 위젯 컴포넌트화:
프레임워크 없이도 위젯을 모듈화하여 개발할 수 있다. HTML 템플릿, CSS 스타일, JavaScript 로직을 별도의 파일로 분리하고, ES6 클래스나 모듈 패턴을 사용하여 재사용 가능한 컴포넌트를 만든다.15
onLoad (초기화), beforeAppear (화면에 표시될 때마다)와 같은 생명주기 메소드를 직접 구현하여 위젯의 동작을 제어할 수 있다.15
- React 기반의 재사용 가능한 위젯 컴포넌트 설계:
React는 웹 위젯 개발에 가장 널리 사용되는 라이브러리 중 하나다.
-
프로젝트 생성:
npx @staffbase/create-widget과 같은 CLI 도구를 사용하면 위젯 개발에 필요한 기본 구조를 빠르게 설정할 수 있다.24 -
컴포넌트 구현: 위젯의 UI와 로직을 하나의 React 컴포넌트로 캡슐화한다. 외부 데이터는
props를 통해 주입받고, 내부 상태는useState훅으로 관리한다. 백엔드 API 호출과 같은 부수 효과(side effect)는useEffect훅을 사용하여 처리한다.20
JavaScript
// React Widget Example
import React, { useState, useEffect } from 'react';
const CurrencyWidget = ({ baseCurrency }) => {
const = useState(null);
useEffect(() => {
fetch(`https://api.exchangerate-api.com/v4/latest/${baseCurrency}`)
.then(res => res.json())
.then(data => setRate(data.rates.USD));
}, [baseCurrency]);
return (
<div className="widget-container">
{rate? `1 ${baseCurrency} = ${rate} USD` : 'Loading...'} </div>
);
};
export default CurrencyWidget;
- 외부 사이트 임베딩 및 스타일 격리:
개발된 웹 위젯은